package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"apibox.club/website"
	//"syscall"
	"time"
)

const (
	START  string = "start"
	STOP   string = "stop"
	STATUS string = "status"
)

func GetBinPath() string {
	file, _ := exec.LookPath(os.Args[0])
	bin_path, _ := filepath.Abs(file)
	bin_path, err := filepath.EvalSymlinks(bin_path)
	if nil != err {
		fmt.Println(err)
		panic(err)
	}
	return bin_path
}

func GetBinDir() string {
	return filepath.Dir(GetBinPath())
}

func GetProjectDir() string {
	dirs := strings.Split(GetBinDir(), string(os.PathSeparator))
	return strings.Join(dirs[:len(dirs)-1], string(os.PathSeparator))
}

type Apibox struct {
	PID int
	cfg *website.Config
}

func (a *Apibox) GetPID() (*Apibox, error) {
	b, err := ioutil.ReadFile(a.cfg.PidPath)
	if nil != err {
		return nil, err
	}
	b = bytes.TrimSpace(b)
	pid, err := strconv.ParseInt(string(b), 10, 32)
	if nil != err {
		return nil, err
	}
	a.PID = int(pid)
	return a, nil
}

func (a *Apibox) Start() error {
	// time.Sleep(time.Duration(1 * time.Second))
	// _, err := a.GetPID()
	// if nil != err {
	// 	return err
	// }
	//if err := syscall.Kill(a.PID, 0); nil != err {
	website.Run(a.cfg)
	//} else {
	//	fmt.Fprintf(os.Stderr, "The program is running, turn off the start again.\n")
	//}
	return nil
}

func (a *Apibox) Stop() error {
	time.Sleep(time.Duration(1 * time.Second))
	_, err := a.GetPID()
	if nil != err {
		return err
	}
	p, err := os.FindProcess(a.PID)
	if nil != err {
		return err
	}
	err = p.Kill()
	if nil != err {
		return err
	}
	return nil
}

func (a *Apibox) Status() (bool, error) {
	_, err := a.GetPID()
	if nil != err {
		return false, err
	}
	// if err := syscall.Kill(a.PID, 0); nil != err {
	// 	return false, nil
	// } else {
	return true, nil
	//}
}

func main() {
	flag.Parse()
	var cmd string = flag.Arg(0)
	cmd = strings.ToLower(cmd)

	root_dir := GetProjectDir()
	fmt.Println("root: ", root_dir)
	cfg, err := website.GetConfig(filepath.Join(root_dir, "conf", "conf.json"))
	if nil != err {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	cfg.RootDir = root_dir
	cfg.TemplatePath = filepath.Join(root_dir, strings.TrimLeft(cfg.TemplateDir, "/"))
	cfg.LogDir = filepath.Join(root_dir, "logs")
	cfg.PidPath = filepath.Join(cfg.LogDir, "pid")
	cfg.MimePath = filepath.Join(root_dir, "conf", "mime.types")

	switch strings.TrimSpace(cmd) {
	case START:
		a := &Apibox{cfg: cfg}
		err := a.Start()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STOP:
		a := &Apibox{cfg: cfg}
		err := a.Stop()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STATUS:
		a := &Apibox{cfg: cfg}
		t, err := a.Status()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
		if !t {
			fmt.Fprintf(os.Stdout, "Stop.\n")
		} else {
			fmt.Fprintf(os.Stdout, "Running...\n")
		}
	default:
		fmt.Fprintf(os.Stderr, "Usage: %s command <start|stop|status>\n", os.Args[0])
	}
}
